/**
 * 
 */
package Phase2;

import java.io.Serializable;

import org.junit.Assert;

/**
 * 
 * State for when a node is the last node in a Perfect HyperCube
 * 
 * @author rpadilla
 *
 */
public class LastState implements NodeState, Serializable
{
	private static final long serialVersionUID = 1L;
	private static  NodeState singleton;
	
	
	/**
	 * private constructor
	 */
	private LastState()
	{
		
	}
	/**
	 * getter of singleton
	 */
	public static NodeState getState()
	{
		if(singleton == null)
		{
			singleton = new LastState();
		}
		return singleton;
	}

	@Override
	public boolean lockState(Node callingNode, boolean rootAccess)
			throws InterruptedException {
		
		return callingNode.acquireAccessPriviledge(rootAccess);
	}
	
	/**
	 * @param callingNode - node to goRight() from
	 * @post return instance of NodeOrRange to goRight to
	 * @see Phase2.NodeState#goRight(Phase2.Node)
	 * @pre callingNode.state instanceOf(LastState)
	 */
	@Override
	public NodeOrRange goRight(Node callingNode, boolean rootAccess) throws InterruptedException
	{			
		if(callingNode.getFold(rootAccess).getId(rootAccess) == 0)
		{
			callingNode.releaseAccessPriviledge();
			return new InsertionRange(callingNode.getFold(rootAccess).getId(rootAccess), callingNode.getFold(rootAccess));
		}
		else
		{
			Node edge = callingNode.getFold(rootAccess);
			if(edge == null)
			{
				callingNode.releaseAccessPriviledge();
				//should NEVER here if code is correct
				throw new IllegalStateException("Fold of Last State is not 0 and"
						+ "the first edge Node is null.  It can't be in Last State.");
			}
			callingNode.releaseAccessPriviledge();
			return edge;
		}
	}
	
	/**
	 * checks if the node's is correctly assigned an lastState
	 * @param node checks this node
	 * @return whether it is in an lastState or not
	 * @pre node != null, node is of the correct state
	 * @post return true if it is the correct state, otherwise false
	 */
	public boolean assertState(Node node) throws InterruptedException
	{
		boolean rootAccess = true;
		
		Assert.assertTrue(node != null);
			
		Assert.assertTrue(node.getDownPointers(rootAccess).size() == 0);
		
		Assert.assertTrue(node.getUpPointers(rootAccess).size() == 0);
			
		Assert.assertTrue(node.getNeighbours(rootAccess).getMax().getId(rootAccess) < node.getId(rootAccess));
		
		return true;
	}
	
	/**
	 * Returns a string representation of the state
	 * @return "LastState"
	 * @pre None
	 * @post return "LastState"
	 */
	public String toString()
	{
		return "LastState";
	}

}
